<?php

namespace IDock\Insurance\JDAL;

use IDock\Common\BaseInterface\BuilderInterface;
use IDock\Http\Request;
use IDock\Http\Response;
use IDock\Insurance\JDAL\Request\AllJDALRequest;
use IDock\Insurance\JDAL\Request\AuthorizationTokenRequest;
use IDock\Insurance\JDAL\Request\ENCPolicyDownloadRequest;
use IDock\Insurance\JDAL\Request\PolicyPaymentRequest;
use IDock\Insurance\JDAL\Response\AllJDALResponse;
use IDock\Insurance\JDAL\Response\ENCPolicyDownloadResponse;
use IDock\Insurance\JDAL\Response\EPolicyDownloadResponse;

class Builder implements BuilderInterface
{

    public function getConfig(): array
    {
        return $this->config;
    }

    protected $token;

    protected $config;

    protected $appId;

    protected $aesSecret;

    protected $md5Secret;

    public function setToken($token)
    {
        $this->token = $token;
    }

    public function execute(Request $request): Response
    {
        /*** @var AllJDALRequest $request */
        $request->loadConfig($this->config);

        $request->setRequestId(md5(uniqid()));

        //登录接口
        if ($request instanceof AuthorizationTokenRequest) {
            $request->setBizParam($this->generate($request));
            return $this->request($request);
        }
        //非登录接口

        //加密
        $this->encrypt($request);

        $request->setHeaders([
            'Content-Type' => 'application/json;charset=UTF-8',
            'appId' => $this->appId,
            'partnerRef' => $request->partnerRef,
            'sign' => $request->getSign(),
            'authorization' => $this->token,
        ]);

        return $this->request($request);
    }

    public function generate(Request $request): array
    {
        return $request->generate();
    }

    public function sign(Request $request): Request
    {
        return $request;
    }

    public function exceptionResponse($request, $errorMessage): Response
    {
        $response = $request->getResponse();

        $response = new $response;
        $response->setCode('500');
        $response->setError($errorMessage);

        return $response;
    }

    public function request(Request $request): Response
    {
        /*** @var AllJDALResponse $response */
        /*** @var AllJDALRequest $request */

        $response = $request->request($request);
        $response->setVisitor($request->getVisitor());

        $isTestResponse = $GLOBALS['testResponse'] ?? '';

        if (!$isTestResponse) {
            $request->responseAfterLogs($response->getBody(), $response->isSuccess());
        }

        if ($response->isSuccess()) {

            if ($request instanceof ENCPolicyDownloadRequest) {
                $this->decrypt($response);
                $response->printerInit();
                return $response;
            }

            if (!$request instanceof AuthorizationTokenRequest) {

                if (!$this->decrypt($response)) {
                    return $response;
                }

                if (!$isTestResponse) {
                    $request->decryptLogs($request->getRequestId(), $response->getBody());
                }
            }

            $response->printerInit();
        }

        return $response;
    }

    /**
     * 加密
     * @param Request $request
     * @return void
     */
    public function encrypt(Request $request)
    {
        /*** @var $request AllJDALRequest */
        $businessNo = $request->businessNo;

        if (!$businessNo) {
            $businessNo = md5(uniqid('', true));
        }

        $toSendData = [
            'head' => [
                'businessNo' => $businessNo
            ]
        ];

        $requestMainData = $request->generate();

        if ($request instanceof PolicyPaymentRequest) {
            $requestMainData['sysSource'] = $this->appId;
        }

        if ($request->requestCode) {
            $toSendData[$request->requestCode] = $requestMainData;
        }

        $request->setPreParameter($toSendData);

        $toEncrypt = json_encode($toSendData, JSON_UNESCAPED_UNICODE);

        $realKey = substr(openssl_digest(openssl_digest($this->aesSecret, 'sha1', true), 'sha1', true), 0, 16);
        $ciphertext = openssl_encrypt($toEncrypt, 'aes-128-ecb', $realKey, OPENSSL_RAW_DATA);
        $encryptString = strtoupper(bin2hex($ciphertext));

        $sign = md5($encryptString . $this->md5Secret);

        $request->setSign($sign);

        $bizParam = [
            'head' => [
                'transactionNo' => $request->getRequestId(),
                'timeStamp' => date('Y-m-d H:i:s')
            ],
            'body' => base64_encode($encryptString)
        ];

        $request->setBizParam($bizParam);
    }

    /**
     * 解密
     * @param AllJDALResponse $response
     * @return void
     */
    public function decrypt(AllJDALResponse $response): bool
    {
        $result = $response->get('result', []);

        $isTestResponse = $GLOBALS['testResponse'] ?? '';
        
        if (!$result) {
            return true;
        }
        
        if ($isTestResponse) {
            $res = $result;
        } else {
            $result = base64_decode($result);

            //对应java AES加密的SHA1PRNG算法
            $realKey = substr(openssl_digest(openssl_digest($this->aesSecret, 'sha1', true), 'sha1', true), 0, 16);
            $res = openssl_decrypt(hex2bin($result), 'aes-128-ecb', $realKey, OPENSSL_RAW_DATA);

            if (!$res) {
                $response->setError('解密失败');
                return false;
            }
        }
        
        if ($response instanceof EPolicyDownloadResponse or $response instanceof  ENCPolicyDownloadResponse) {
            $response->setResult($res);
        } else {
            $response->setResult(json_decode($res, true));
        }

        return true;
    }
}


